package com.glodon.paas.databag.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.glodon.paas.databag.api.bean.ResourceDto;
import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;

@Component
public class WebService {

	private final Logger logger = LoggerFactory.getLogger(WebService.class);
    private final DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
    @Value("${document.storage.url}")
    private String storageUrl1;
    @Value("${api.internal.document.url}")
    private String documentInternalUrl;
    @Value("#{systemProperties['java.io.tmpdir']}")
    private String tempDirctory;
    private final RestTemplate template = new RestTemplate();
	private static final ClientConfig clientConfig;
	static {
		clientConfig = new DefaultClientConfig();
		clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
	}
	
    public InputStream getResource(String key) {
        String url = storageUrl1.trim() + "{key}";
        try {
            ResponseEntity<byte[]> entity = template.getForEntity(url, byte[].class, key);
            HttpStatus httpStatus = entity.getStatusCode();
            if (HttpStatus.NOT_FOUND.equals(httpStatus)) {
                throw PaasServerExceptionFactory.notFoundException("can't find resource:" + key, null);
            }
            byte[] bytes = entity.getBody();
            InputStream is = new ByteArrayInputStream(bytes);
            return is;
        } catch (RestClientException e) {
            if (e instanceof HttpClientErrorException) {
                throw PaasServerExceptionFactory.notFoundException("can't find resource:" + key, null);
            } else {
                throw PaasServerExceptionFactory.internalAPIException("get resource from document store failed:" + key,
                        e);
            }
        }
    }

    public void postResource(String key, final InputStream is, long length) {
        String url = storageUrl1.trim() + "{key}?fileSize={length}";
        template.execute(url, HttpMethod.POST, new RequestCallback() {
            @Override
            public void doWithRequest(ClientHttpRequest req) throws IOException {
                req.getHeaders().add("Content-Type", "application/octet-stream");
                OutputStream outputStream = req.getBody();
                IOUtils.copy(is, outputStream);
            }
        }, null, key, length);
    }

    public String downloadFile(final String url) {
        String file = template.execute(url, HttpMethod.GET, null, new ResponseExtractor<String>() {
            @Override
            public String extractData(ClientHttpResponse resp) {
                try {
                    InputStream inputStream = resp.getBody();
                    String disposition = resp.getHeaders().getFirst("Content-Disposition");
                    String fileName = StringUtils.substringBetween(disposition, "=\"", "\"");
                    if (fileName == null) {
                        throw PaasServerExceptionFactory.documentException(
                                "can't get file name from 'Content-Disposition' Header:" + disposition, null);
                    }
                    String suffix = "";
                    int index = fileName.lastIndexOf(".");
                    if (index < 0) {
                        throw PaasServerExceptionFactory.documentException(
                                "can't get file suffix from 'Content-Disposition' Header:" + disposition, null);
                    }
                    suffix = fileName.substring(index);
                    File tempFile = File.createTempFile(getPrefix(), suffix, new File(tempDirctory));
                    OutputStream os = new FileOutputStream(tempFile);
                    IOUtils.copy(inputStream, os);
                    return tempFile.getPath();
                } catch (IOException e) {
                    logger.error("download file failed:" + url, e);
                    throw PaasServerExceptionFactory.storageException("download file failed:" + url, e);
                }
            }
        });
        return file;
    }

    public ResourceDto downloadResource(final String url) {
        ResponseEntity<byte[]> entity = template.getForEntity(url, byte[].class);
        byte[] body = entity.getBody();
        HttpHeaders headers = entity.getHeaders();
        String disposition = headers.getFirst("Content-Disposition");
        String fileName = StringUtils.substringBetween(disposition, "=\"", "\"");
        if (fileName == null) {
            throw PaasServerExceptionFactory.documentException("can't get file name from 'Content-Disposition' Header:"
                    + disposition, null);
        }
        long length = headers.getContentLength();
        ResourceDto resource = new ResourceDto(fileName, new ByteArrayInputStream(body), length, null);
        return resource;

    }
    
    public void deleteResource(String key) {
        logger.info("deleting resource: {}", key);
        template.delete(storageUrl1.trim() + key);
        logger.info("deleted resource: {}", key);
    }

    /**
     * @param tempDirctory
     *            the tempDirctory to set
     */
    public void setTempDirctory(String tempDirctory) {
        this.tempDirctory = tempDirctory;
    }

    public void setDocumentUrl(String documentUrl) {
        this.storageUrl1 = documentUrl.trim();
    }

    private String getPrefix() {
        return formatter.format(new Date());
    }
	
}
